Behind the Scenes

Tom Elliott

satRdays Auckland 2020

Part I

What is iNZight, and who uses it?

library(iNZight)
iNZight()

iNZight main window

  • <span class="fa-li"><i class="fas fa-check-circle"></i></span>
    <img src="assets/images/Rlogo.svg" class="logo" > package!
  • <span class="fa-li"><i class="fas fa-check-circle"></i></span>
    GUI for __visually exploring__ data
  • <span class="fa-li"><i class="fas fa-check-circle"></i></span>
    __easy-to-learn__ tool for students/beginners ...
  • <span class="fa-li"><i class="fas fa-check-circle"></i></span>
    ... but also non-beginners!

  • <span class="fa-li"><i class="fas fa-check-circle"></i></span>
    <img src="assets/images/Rlogo.svg" class="logo" > package!
  • <span class="fa-li"><i class="fas fa-check-circle"></i></span>
    GUI for __visually exploring__ data
  • <span class="fa-li"><i class="fas fa-check-circle"></i></span>
    __easy-to-learn__ tool for students/beginners ...
  • <span class="fa-li"><i class="fas fa-check-circle"></i></span>
    ... but also non-beginners!
  • <span class="fa-li"><i class="fas fa-check-circle"></i></span>
    bridge between __GUI__ and __coding__

Data

GUI

Explore

Save script

Part II

The development of iNZight

Another child of the University of Auckland

  • <span class="fa-li"><i class="fas fa-brain"></i></span>
    Chris Wild
  • <span class="fa-li"><i class="fas fa-users"></i></span>
    Statistics __students__

How does it work?

gWidgets2 + gWidgets2RGtk2† RGtk2‡ GTK

† John Verzani ‡ Michael Lawrence

Started off small …

  • <span class="fa-li"><i class="fas fa-plus-circle"></i></span>
    a __feature__ here ...
  • <span class="fa-li"><i class="fas fa-plus-circle"></i></span>
    a __module__ there ...

… et voilà: a rewrite was needed!

  • <span class="fa-li"><i class="fas fa-terminal"></i></span>
    Object Oriented Programming (OOP)
  • <span class="fa-li"><i class="fas fa-terminal"></i></span>
    Separability
  • <span class="fa-li"><i class="fas fa-terminal"></i></span>
    Reactivity
  • <span class="fa-li"><i class="fas fa-terminal"></i></span>
    Extensibility

Object Oriented Programming

  • <span class="fa-li"><i class="fas fa-code"></i></span>
    reference classes
  • <span class="fa-li"><i class="fas fa-code"></i></span>
    each __component__ of the UI is represented by a __class__
  • <span class="fa-li"><i class="fas fa-code"></i></span>
    classes have __properties__ ("fields") and __methods__

LoadDataWindow <- setRefClass("LoadDataWindow",
    fields = list(
        filename = "character"
    ),
    methods = list(
        initialize = function(...) {
            w <- gwindow("Load data")
            g <- ggroup(horizontal = FALSE, container = w)

            # Get filename from user
            fileedit <- gedit(container = g)

            # Load data
            loadbtn <- gbutton("Load", container = g)

            addHandlerKeystroke(fileedit,
                handler = function(h, ...) {
                    filename <<- svalue(h$obj)
                }
            )

            addHandlerClicked(loadbtn, function(h, ...) loadData())
        },
        loadData = function() {
            data <- read.csv(filename)
        }
    )
)

Demo Load Window

iNZight main window

Separability

  • <span class="fa-li"><i class="fas fa-code"></i></span>
    keep UI and data logic separate
  • <span class="fa-li"><i class="fas fa-code"></i></span>
    UI inputs control arguments to a __single function__
  • <span class="fa-li"><i class="fas fa-code"></i></span>
    existing or new __wrapper__ for another __package__

LoadDataWindow <- setRefClass("LoadDataWindow",
    fields = list(
        filename = "character"
    ),
    methods = list(
        initialize = function() { ... },
        loadData = function() {
            data <- read.csv(filename)
        }
    )
)

LoadDataWindow <- setRefClass("LoadDataWindow",
    fields = list(
        filename = "character",
        filetype = "character",
        delimiter = "character", # csv can use , or ;
        ...
    ),
    methods = list(
        initialize = function(...),
        loadData = function() {
            if (filetype == "csv") {
                data <- read.csv(filename, delimiter = delimiter, ...)
            } else if (filetype == "excel") {
                data <- readxl::read_xls(filename, ...)
            } else ...
        }
    )
)

LoadDataWindow <- setRefClass("LoadDataWindow",
    fields = list(
        filename = "character",
        filetype = "character",
        delimiter = "character", # csv can use , or ;
        ...
    ),
    methods = list(
        initialize(...),
        loadData = function() {
            data <- iNZightTools::smart_read(filename,
                filetype = filetype,
                delim = delimiter,
                ...
            )
        }
    )
)

Reactivity

  • <span class="fa-li"><i class="fas fa-code"></i></span>
    <strong>Instant</strong> feedback
  • <span class="fa-li"><i class="fas fa-code"></i></span>
    Makes <strong>exploring</strong> data <strong>faster and easier</strong>
  • <span class="fa-li"><i class="fas fa-code"></i></span>
    Widget <strong>handlers</strong> and <strong>separability</strong>

Demo <- setRefClass("Demo",
    field = list(
        data = "data.frame",
        colour = "character"
    ),
    methods = list(
        initialize = function() {
            w <- gwindow("Demo")
            g <- ggroup(horizontal = FALSE, container = w)
            col <- gcombobox(
                c("Orangered", "Goldenrod", "Steelblue"),
                container = g,
                handler = function(h, ...) {
                    colour <<- svalue(h$obj)
                    draw()
                }
            )

            data <<- data.frame(x = rnorm(100), y = rnorm(100))
            colour <<- "Orangered"

            draw()
        },
        draw = function() {
            plot(y ~ x,
                data = data,
                col = colour
            )
        }
    )
)

Extensibility

  • <span class="fa-li"><i class="fas fa-code"></i></span>
    <strong>Foresight</strong> and <strong>planning</strong>
  • <span class="fa-li"><i class="fas fa-code"></i></span>
    Add <strong>new</strong> or change <strong>existing</strong> features ...
  • <span class="fa-li"><i class=""></i></span>
    ... without rewriting everything!
  • <span class="fa-li"><i class="fas fa-code"></i></span>
    <strong>OOP:</strong> add new classes, inheritance, ...
  • <span class="fa-li"><i class="fas fa-code"></i></span>
    <strong>Separability:</strong> new field = new argument<br>everything else unchanged
  • <span class="fa-li"><i class="fas fa-code"></i></span>
    A system for adding __completely new__ modules

DemoModule <- setRefClass(
    "Demo Module",
    contains = "CustomModule",
    fields = list(
        GUI = "ANY",
        ...
    ),
    methods = list(
        initialize = function(gui, name) {
            callSuper(gui,
                name = name,
                embedded = TRUE
            )
            ...
        },
        ...
    )
)

Thank you

Slides: bit.ly/iNZightSatRday